package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.CommonStatusEnum;
import com.ruoyi.common.enums.DataScopeEnum;
import com.ruoyi.common.enums.RoleCodeEnum;
import com.ruoyi.common.exception.tenant.TenantException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.tenant.TenantContextHolder;
import com.ruoyi.common.utils.tenant.TenantUtils;
import com.ruoyi.system.domain.SysTenant;
import com.ruoyi.system.domain.SysTenantPackage;
import com.ruoyi.system.domain.vo.SysTenantCreateVo;
import com.ruoyi.system.mapper.SysTenantMapper;
import com.ruoyi.system.service.*;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 租户Service业务层处理
 * 
 * @author ruoyi
 * @date 2022-09-07
 */
@Service
public class SysTenantServiceImpl implements ISysTenantService
{
    private final static Logger log  = LoggerFactory.getLogger(SysTenantServiceImpl.class);

    @Autowired
    private SysTenantMapper sysTenantMapper;

    @Autowired
    private ISysTenantPackageService packageService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysUserService userService;

    /**
     * 查询租户
     * 
     * @param id 租户主键
     * @return 租户
     */
    @Override
    public SysTenant selectSysTenantById(Long id)
    {
        return sysTenantMapper.selectSysTenantById(id);
    }

    @Override
    public SysTenant selectSysTenantByName(String name) {
        return sysTenantMapper.selectSysTenantByName(name);
    }

    /**
     * 查询租户列表
     * 
     * @param sysTenant 租户
     * @return 租户
     */
    @Override
    public List<SysTenant> selectSysTenantList(SysTenant sysTenant)
    {
        return sysTenantMapper.selectSysTenantList(sysTenant);
    }

    @Override
    public List<SysTenant> getTenantListByPackageId(Long packageId) {
        SysTenant sysTenant = new SysTenant();
        sysTenant.setPackageId(packageId);
        sysTenant.setDeleted(0);
        sysTenant.setStatus("0");
        return sysTenantMapper.selectSysTenantList(sysTenant);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) {
        TenantUtils.execute(tenantId, () -> {
            List<SysRole> roleList = roleService.selectRoleAll();
            roleList.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配",
                    role.getRoleId(), role.getTenantId(), tenantId));

            roleList.forEach(role -> {
                // 如果是租户管理员，重新分配其权限为租户套餐的权限
                if (Objects.equals(role.getRoleKey(), RoleCodeEnum.TENANT_ADMIN.getCode())) {
                    role.setMenuIds(menuIds.toArray(new Long[menuIds.size()]));
                    roleService.updateRole(role);
                    log.info("[updateRole][租户管理员({}/{}) 的权限修改为({})]", role.getRoleId(), role.getTenantId(), menuIds);
                    return;
                }
                // 如果是其他角色，则去掉超过套餐的权限
                List<Long> roleMenuIds = menuService.selectMenuListByRoleId(role.getRoleId());
                Set<Long> menuIdSet = CollUtil.intersectionDistinct(new HashSet<>(roleMenuIds), menuIds);
                role.setMenuIds(menuIdSet.toArray(new Long[menuIdSet.size()]));
                roleService.updateRole(role);
                log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getRoleId(), role.getTenantId(), roleMenuIds);
            });
        });
    }

    /**
     * 新增租户
     * 
     * @param sysTenant 租户
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertSysTenant(SysTenantCreateVo sysTenant)
    {
        SysTenantPackage tenantPackage = packageService.validTenantPackage(sysTenant.getPackageId());
        int rs = sysTenantMapper.insertSysTenant(sysTenant);
        Long tenantId = TenantContextHolder.getTenantId();
        try {
            TenantContextHolder.setTenantId(sysTenant.getId());
            SysRole role = createRole(tenantPackage);

            Long userId = createUser(sysTenant, role);

            SysTenant tenant = new SysTenant();
            tenant.setId(tenant.getId());
            tenant.setContactUserId(userId);
            sysTenantMapper.updateSysTenant(tenant);
       }finally {
            TenantContextHolder.setTenantId(tenantId);
        }
        return rs;
    }

    @NotNull
    private Long createUser(SysTenantCreateVo sysTenant, SysRole role) {
        SysUser user = new SysUser();
        user.setUserName(sysTenant.getUsername());
        user.setNickName(sysTenant.getContactName());
        user.setPassword(SecurityUtils.encryptPassword(sysTenant.getPassword()));
        user.setRoleIds(new Long[]{role.getRoleId()});
        user.setStatus(CommonStatusEnum.ENABLE.getStatus());
        user.setDelFlag("0");
        user.setRemark("系统自动创建");
        userService.insertUser(user);
        return user.getUserId();
    }

    private SysRole createRole( SysTenantPackage tenantPackage) {
        SysRole role = new SysRole();
        role.setRoleName(RoleCodeEnum.TENANT_ADMIN.getName());
        role.setRoleKey(RoleCodeEnum.TENANT_ADMIN.getCode());
        role.setRemark("系统自动创建");
        role.setDataScope(DataScopeEnum.ALL.getScope());
        role.setDeptCheckStrictly(true);
        role.setDeptCheckStrictly(true);
        role.setRoleSort("2");
        role.setStatus(CommonStatusEnum.ENABLE.getStatus());
        role.setMenuIds(tenantPackage.getMenuIds().toArray(new Long[tenantPackage.getMenuIds().size()]));
        role.setDelFlag("0");
        roleService.insertRole(role);
        return role;
    }
    /**
     * 修改租户
     * 
     * @param sysTenant 租户
     * @return 结果
     */
    @Override
    public int updateSysTenant(SysTenant sysTenant)
    {
        return sysTenantMapper.updateSysTenant(sysTenant);
    }

    /**
     * 批量删除租户
     * 
     * @param ids 需要删除的租户主键
     * @return 结果
     */
    @Override
    public int deleteSysTenantByIds(Long[] ids)
    {
        return sysTenantMapper.deleteSysTenantByIds(ids);
    }

    /**
     * 删除租户信息
     * 
     * @param id 租户主键
     * @return 结果
     */
    @Override
    public int deleteSysTenantById(Long id)
    {
        return sysTenantMapper.deleteSysTenantById(id);
    }

    @Override
    public List<Long> getTenantIds() {
        SysTenant query = new SysTenant();
        query.setDeleted(0);
        query.setStatus(CommonStatusEnum.ENABLE.getStatus());
        List<SysTenant> tenantList = sysTenantMapper.selectSysTenantList(query);
        return tenantList.stream().map(SysTenant::getId).collect(Collectors.toList());
    }

    @Override
    public void validTenant(Long id) {
        SysTenant tenant = sysTenantMapper.selectSysTenantById(id);
        if (tenant == null){
            throw TenantException.TenantNotExistsException();
        }
        if (tenant.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())){
            throw TenantException.TenantDisableException(tenant.getName());
        }
        if (tenant.getExpireTime().before(new Date())){
            throw TenantException.TenantExpireException();
        }
    }
}
